use super::*;
use crate::llm::Message;
use regex::Regex;
use serde::{Deserialize, Serialize};
use tracing::{debug, info};

pub const GEN_FILES_PATH: &str = "./files/rust";

// Performs call to LLM GPT
pub async fn ai_task_request(
    msg_context: Vec<Message>,
    agent_position: &str,
    llm: Arc<Mutex<Box<dyn LLM + 'static>>>,
) -> String {
    let mut llm = llm.lock().await;
    // Get LLM response
    let llm_response_res: Result<String, Box<dyn std::error::Error + Send>> =
        llm.call(msg_context.clone()).await;

    // Return Success or try again
    match llm_response_res {
        Ok(llm_resp) => llm_resp,
        Err(_) => llm
            .call(msg_context.clone())
            .await
            .expect("Failed twice to call OpenAI"),
    }
}

// =======================================
// 本来想验证大模型输出，但是幻觉不稳定，验证困难，后面再对齐业内最佳实践
// 现在换思路解决：Agent 自动重试，10次内无法解决的问题 -> 切换手动人工引导 -> 合适时再启动 Agent 自动执行

pub fn clean_and_fix_json(input: &str) -> String {
    // 使用正则表达式匹配所有控制字符，包括换行符（\n，0x0A）和回车符（\r，0x0D）
    let control_chars_regex = Regex::new(r"[\x00-\x1F\x7F]").unwrap();
    let mut cleaned_input = control_chars_regex.replace_all(input, "").to_string();
    cleaned_input = cleaned_input.replace("\\n", "");

    // 检查字符串是否以闭合的花括号结束
    if !cleaned_input.trim_end().ends_with('}') {
        // 直接在字符串末尾添加闭合的花括号
        cleaned_input.push('}');
    }
    // 如果字符串以闭合的花括号结束，检查 '}' 前面是否有闭合的双引号
    if let Some(last_brace_position) = cleaned_input.rfind('}') {
        // 从最后一个 '}' 到字符串开始，找到第一个非空白字符
        let pre_brace_chars = cleaned_input[..last_brace_position].chars().rev();
        let non_whitespace_position = pre_brace_chars.clone().position(|c| !c.is_whitespace());

        if let Some(pos) = non_whitespace_position {
            // 如果最后一个非空白字符不是双引号，则在 '}' 前添加一个双引号
            if pre_brace_chars.skip(pos).next() != Some('"') {
                let (start, end) = cleaned_input.split_at(last_brace_position);
                cleaned_input = format!("{}\"{}", start, end);
            }
        }
    }

    // 步骤 1: 替换所有的 `\"` 为 `"`
    let mut processed_str = cleaned_input.replace("\\\"", "\"");

    // Step 2: Correctly replace quotes within ```rust ... ``` blocks.
    let rust_code_start = "```rust";
    let rust_code_end = "```";
    let mut new_str = String::new();
    let mut start_search_index = 0;

    while let Some(start) = processed_str[start_search_index..].find(rust_code_start) {
        let start = start + start_search_index;
        let end =
            if let Some(end) = processed_str[start + rust_code_start.len()..].find(rust_code_end) {
                end + start + rust_code_start.len() + rust_code_end.len()
            } else {
                processed_str.len() // If no end is found, use the end of the string
            };

        // Append everything up to the code block unchanged
        new_str.push_str(&processed_str[start_search_index..start]);

        // For the code block, replace " with \"
        // Need to correct for the start offset of the code block
        let code_block = &processed_str[start..end].replace("\"", "\\\"");
        new_str.push_str(code_block);

        start_search_index = end;
    }

    // Append any remaining part of the string after the last code block
    new_str.push_str(&processed_str[start_search_index..]);

    new_str = new_str.replace("```\"", "```\\\"");
    info!("-------------------------");
    info!("-----------clean Processed JSON String:\n {new_str:?}");

    new_str
}

pub async fn decode_llm_output(raw_code: &str) -> String {
    // Decode LLM Output
    // 对于 prompt 指定输出格式
    #[derive(Serialize, Deserialize, Debug)]
    struct CodeSnippet {
        // FIXME: Try use `Value`
        plan: String,
        code: String,
    }
    // FIXED ME
    // BUG: 与 LLM 请求超过一定次数，raw_code 会为空，需要查验
    let json_str = capture_json_code(raw_code).unwrap();
    info!("--- Input JSON --- {:#?}", json_str);

    // Step 1: Clean the input JSON string
    let cleaned_json_str = clean_and_fix_json(&json_str);

    info!("--- Cleaned JSON --- {:#?}", cleaned_json_str);

    // BUG =====
    // Step 2: Deserialize, validate and possibly fix the JSON structure
    let mut snippet: CodeSnippet = match serde_json::from_str(&cleaned_json_str) {
        Ok(snip) => snip,
        Err(err) => {
            info!("Error deserializing JSON: {}", err);
            return String::default();
        }
    };

    // Ensure the code starts and ends correctly
    if !snippet.code.trim_start().starts_with("```rust") {
        snippet.code = format!("```rust\n{}", snippet.code.trim_start());
    }
    if !snippet.code.trim_end().ends_with("```") {
        snippet.code = format!("{}\n```", snippet.code.trim_end());
    }

    // Optional: Print the cleaned and fixed snippet
    info!("Cleaned and Fixed Snippet: {:?}", snippet);

    match serde_json::to_string_pretty(&cleaned_json_str) {
        Ok(json) => {
            info!("Final JSON:\n{}", json);
            json
        }
        Err(err) => {
            info!("Error serializing to JSON: {}", err);
            cleaned_json_str
        }
    }
}
// =======================================
